import numpy as np


import numpy as np

SCALE = 100  # 放大倍数，保留两位小数
TOLERANCE = 1e-5
def embedSecretWithDe(
    originalSequence: list[np.float32], secretBits: list[np.uint8], precision=9
) -> tuple[list[np.float32], list[bool]]:
    seq = np.array(originalSequence, dtype=np.float64)  # 使用 float64 提高精度
    isOdd = len(seq) % 2 != 0
    maxIdxAvailable = len(seq) - 1 if isOdd else len(seq)

    maxCapacity = maxIdxAvailable // 2
    if len(secretBits) > maxCapacity:
        raise ValueError(f"秘密信息过长，最大容量为{maxCapacity}位")

    paddedSecret = np.pad(secretBits, (0, maxCapacity - len(secretBits)), mode='constant')

    embedded = []
    swapFlags = []

    for i in range(0, maxIdxAvailable, 2):
        a, b = seq[i], seq[i+1]
        swap = False
        if b < a:
            a, b = b, a
            swap = True
        swapFlags.append(swap)

        d = b - a
        m = (a + b) / 2.0  # 浮点平均

        bit = paddedSecret[i//2]
        d_prime = 2.0 * d + float(bit)

        a_prime = m - d_prime / 2.0
        b_prime = m + d_prime / 2.0

        # 四舍五入到指定精度
        a_prime = round(a_prime, precision)
        b_prime = round(b_prime, precision)

        if swap:
            a_prime, b_prime = b_prime, a_prime

        embedded.extend([a_prime, b_prime])

    if isOdd:
        embedded.append(seq[-1])

    return np.array(embedded, dtype=np.float32), np.array(swapFlags)

def embedSecretWithDeOld(
    originalSequence: list[np.float32], secretBits: list[np.uint8], precision=9
) -> tuple[list[np.float32], list[bool]]:
    seq = np.array(originalSequence)
    ints = [int(round(x * SCALE)) for x in seq]
    isOdd = len(ints) % 2 != 0
    maxIdxAvailable = len(ints) - 1 if isOdd else len(ints)

    maxCapacity = maxIdxAvailable // 2
    if len(secretBits) > maxCapacity:
        raise ValueError(f"秘密信息过长，最大容量为{maxCapacity}位")

    paddedSecret = np.pad(secretBits, (0, maxCapacity - len(secretBits)), mode='constant')

    embedded_ints = []
    swapFlags = []

    for i in range(0, maxIdxAvailable, 2):
        a, b = ints[i], ints[i+1]
        swap = False
        if b < a:
            a, b = b, a
            swap = True
        swapFlags.append(swap)

        d = b - a
        m = (a + b) // 2  # 整数平均（向下取整）

        bit = paddedSecret[i//2]
        d_prime = 2 * d + bit

        # 重构新值
        a_prime = m - d_prime // 2
        b_prime = m + d_prime - d_prime // 2  # 补偿整数除法

        embedded_ints.extend([a_prime, b_prime])

    if isOdd:
        embedded_ints.append(ints[-1])

    # 转回浮点
    embedded_floats = [round(x / SCALE, precision) for x in embedded_ints]
    return np.array(embedded_floats), np.array(swapFlags)
def extractSecretWithDe(
    embeddedSequence: list[np.float32],
    secretLength: int,
    swapFlags: list[bool],
    precision=9,
) -> tuple[list[np.uint8], list[np.float32]]:
    seq = np.array(embeddedSequence, dtype=np.float64)
    isOdd = len(seq) % 2 != 0
    maxIdxAvailable = len(seq) - 1 if isOdd else len(seq)

    if len(swapFlags) != maxIdxAvailable // 2:
        raise ValueError("交换标记长度不匹配")

    extracted = []
    recovered = []

    for i in range(0, maxIdxAvailable, 2):
        a_prime, b_prime = seq[i], seq[i+1]
        swap = swapFlags[i//2]

        if swap:
            a_prime, b_prime = b_prime, a_prime

        d_prime = b_prime - a_prime
        m = (a_prime + b_prime) / 2.0

        # 提取比特：先 round d_prime 到最近数，再取奇偶
        bit = int(round(d_prime)) & 1
        extracted.append(bit)

        # 恢复原始差值
        d = (d_prime - bit) / 2.0

        # 恢复原始值
        a = m - d
        b = m + d

        a = round(a, precision)
        b = round(b, precision)

        if swap:
            a, b = b, a

        recovered.extend([a, b])

    if isOdd:
        recovered.append(seq[-1])

    extracted = extracted[:secretLength]
    return np.array(extracted, dtype=np.uint8), np.array(recovered, dtype=np.float32)

def extractSecretWithDeOld3(
    embeddedSequence: list[np.float32],
    secretLength: int,
    swapFlags: list[bool],
    precision=9,
) -> tuple[list[np.uint8], list[np.float32]]:
    seq = np.array(embeddedSequence)
    ints = [int(round(x * SCALE)) for x in seq]

    isOdd = len(ints) % 2 != 0
    maxIdxAvailable = len(ints) - 1 if isOdd else len(ints)

    if len(swapFlags) != maxIdxAvailable // 2:
        raise ValueError("交换标记长度不匹配")

    extracted = []
    recovered_ints = []

    for i in range(0, maxIdxAvailable, 2):
        a_prime, b_prime = ints[i], ints[i+1]
        swap = swapFlags[i//2]

        if swap:
            a_prime, b_prime = b_prime, a_prime

        d_prime = b_prime - a_prime
        total = a_prime + b_prime

        # 提取比特
        bit = d_prime & 1
        extracted.append(bit)

        # 恢复原始差值
        d = (d_prime - bit) // 2

        # 恢复原始值（注意：total 可能为奇数）
        a = (total - d_prime) // 2 + bit  # 调整补偿
        b = (total + d_prime) // 2

        # 更稳健：用 m 和 d 恢复
        m = total // 2
        a = m - d
        b = m + d + (total % 2)  # 补偿奇偶

        if swap:
            a, b = b, a

        recovered_ints.extend([a, b])

    if isOdd:
        recovered_ints.append(ints[-1])

    recovered_floats = [round(x / SCALE, precision) for x in recovered_ints]
    extracted = extracted[:secretLength]

    return np.array(extracted, dtype=np.uint8), np.array(recovered_floats, dtype=np.float32)

def embedSecretWithDeOld2(
    originalSequence: list[np.float32], secretBits: list[np.uint8], precision=9
) -> list[np.float32]:
    """
    将秘密信息嵌入到浮点数序列中
    参数:
        originalSequence: 原始浮点数序列, numpy.float32
        secretBits: 待嵌入的秘密信息，二进制列表, list[numpy.uint8]
    返回:
        embeddedSequence: 嵌入秘密信息后的浮点数序列
        swapFlags: 记录交换位置的标记
    """
    # 复制原始序列以避免修改
    seq = originalSequence.copy()
    originalLength = len(seq)

    # 处理奇数长度序列
    isOdd = len(seq) % 2 != 0
    maxIdxAvailable = len(seq) - 1 if isOdd else len(seq)

    # 检查容量
    maxCapacity = maxIdxAvailable // 2
    if len(secretBits) > maxCapacity:
        raise ValueError(f"秘密信息过长，最大容量为{maxCapacity}位")

    # 填充秘密信息
    paddedSecret = np.pad(
        secretBits, (0, maxCapacity - len(secretBits)), mode="constant"
    )

    embedded = []
    swapFlags = []

    # 处理每一对元素
    for i in range(0, maxIdxAvailable, 2):
        a, b = seq[i], seq[i + 1]
        swap = False

        # 确保b >= a，否则交换
        if b < a:
            a, b = b, a
            swap = True
        swapFlags.append(swap)

        # 计算差值和平均值
        d = b - a  # 原始差值
        m = (a + b) / 2  # 平均值，嵌入后保持不变

        # 获取当前秘密比特
        bit = paddedSecret[i // 2]

        # 差值扩展：d' = 2d + bit
        dPrime = 2 * d + bit

        # 计算嵌入后的新值
        aPrime = m - dPrime / 2
        bPrime = m + dPrime / 2

        # 四舍五入到指定精度
        aPrime = round(aPrime, precision)
        bPrime = round(bPrime, precision)

        # 如果之前交换过，现在交换回来
        if swap:
            aPrime, bPrime = bPrime, aPrime

        embedded.extend([aPrime, bPrime])

    # 恢复原始长度
    if isOdd:
        embedded.append(seq[-1])  # 附加最后一个

    return np.array(embedded), np.array(swapFlags)

def extractSecretWithDe(
    embeddedSequence: list[np.float32],
    secretLength: int,
    swapFlags: list[bool],
    precision=9,
) -> tuple[list[np.uint8], list[np.float32]]:
    """
    从嵌入序列中提取秘密信息并恢复原始序列
    """
    seq = embeddedSequence.copy()
    isOdd = len(seq) % 2 != 0
    maxIdxAvailable = len(seq) - 1 if isOdd else len(seq)

    if len(swapFlags) != maxIdxAvailable // 2:
        raise ValueError("交换标记长度不匹配")

    extracted = []
    recovered = []

    for i in range(0, maxIdxAvailable, 2):
        a_prime, b_prime = seq[i], seq[i + 1]
        swap = swapFlags[i // 2]

        if swap:
            a_prime, b_prime = b_prime, a_prime

        d_prime = b_prime - a_prime
        m = (a_prime + b_prime) / 2.0

        # 提取秘密比特
        bit = int(round(d_prime)) & 1  # 更鲁棒
        extracted.append(bit)

        # 恢复原始差值
        d = (d_prime - bit) / 2.0

        # 恢复原始值
        a = m - d
        b = m + d

        a = round(a, precision)
        b = round(b, precision)

        if swap:
            a, b = b, a

        recovered.extend([a, b])

    # 如果是奇数长度，保留最后一个元素
    if isOdd:
        recovered.append(seq[-1])

    # 只返回需要的秘密位数
    extracted = extracted[:secretLength]

    return np.array(extracted, dtype=np.uint8), np.array(recovered, dtype=np.float32)

def extractSecretWithDeOld(
    embeddedSequence: list[np.float32],
    secretBits: list[np.uint8],
    swapFlags: list[np.float32],
    precision=9,
) -> list[list[np.float32], list[np.float32]]:
    """
    从嵌入序列中提取秘密信息并恢复原始序列
    embeddedSequence:嵌入有信息的序列， list[np.float32],
    secretBits: 秘密数据的长度，list[np.uint8],
    swapFlags: 交换标志，list[np.float32],
    precision=9,
    """
    # 复制嵌入序列

    seq = embeddedSequence.copy()
    originalLength = len(seq)

    # 处理奇数长度
    isOdd = len(seq) % 2 != 0
    maxIdxAvailable = len(seq) - 1 if isOdd else len(seq)

    # 检查标记长度
    if len(swapFlags) != maxIdxAvailable // 2:
        raise ValueError("交换标记长度不匹配")

    extracted = []
    recovered = []
    pairNum = min(secretBits, len(swapFlags), maxIdxAvailable // 2)
    # 处理每一对元素
    for i in range(0, pairNum, 2):
        aPrime, bPrime = seq[i], seq[i + 1]
        swap = swapFlags[i // 2]
        # 如果之前交换过，先交换回来
        if swap:
            aPrime, bPrime = bPrime, aPrime
        # 计算新差值和平均值
        dPrime = bPrime - aPrime
        m = (aPrime + bPrime) / 2  # 与原始平均值相同
        # 提取秘密比特 (0或1)
        # 使用四舍五入确保正确提取，因为浮点数可能有微小误差
        bit = round(dPrime % 2)
        extracted.append(bit)
        # 恢复原始差值
        d = (dPrime - bit) / 2
        # 恢复原始值
        a = m - d / 2
        b = m + d / 2
        # 四舍五入到指定精度
        a = round(a, precision)
        b = round(b, precision)
        # 如果之前交换过，交换回来
        if swap:
            a, b = b, a
        recovered.extend([a, b])

    # 恢复原始长度
    for j in range(len(recovered),len(embeddedSequence)):  # 恢复原始长度
        recovered.append(embeddedSequence[j])

    return np.array(extracted), np.array(recovered)

if __name__ == "__main__":
    original = np.array([3.2, 5.6, 1.8, 4.3, 6.7, 2.9, 8.1, 9.2, 10.1], dtype=np.float32)
    secret = np.array([1, 0, 1, 0], dtype=np.uint8)

    print("原始序列:", original)
    print("秘密信息:", secret)

    embedded, flags = embedSecretWithDe(original, secret, precision=6)
    print("嵌入后:", embedded)

    extracted, recovered = extractSecretWithDe(embedded, len(secret), flags, precision=6)
    print("提取:", extracted)
    print("恢复:", recovered)

    print("准确:", np.allclose(original, recovered, atol=1e-5))